#include <assert.h>
#include <string.h>
#include <stdbool.h>
#include <stdio.h>
#include "sm2.h"
#include "sm3.h"

#ifdef CF_CRYPTO_XMEN_INTEGRATION
#include "Os.h"
void sm2_yield_cpu() {
    Schedule();
}
#else
void sm2_yield_cpu() {
    // nop
}
#endif

// Output Formatting
#define SM2_SHOW_BYTE_WITH_SPACE 0

// ============================================================================
// SM2 Constant
// ============================================================================
#define SM2_HASH_RESULT_BYTES   32
#define SM2_HASH_RESULT_BITS    256
#define SM2_HASH_BUFFER_BYTES   64
#define SM2_HASH_BUFFER_BITS    512
#define SM2_BIGINT_DATA_SIZE    32
#define SM2_BIGINT_DATA_LEN     8
#define SM2_BIGINT_DATA_BYTES   32

// ----------------------------------------------------------------------------
// Static Storage
// ----------------------------------------------------------------------------
static sm2_ctx sm2_ctx_instance;
sm2_ctx *sm2_ctx_shared() {
    return &sm2_ctx_instance;
}

// ----------------------------------------------------------------------------
// Helper functions
// ----------------------------------------------------------------------------
int sm2_helper_hex2i(char c) {
    if (c >= '0' && c <= '9') {
        return c - '0';
    } else if (c >= 'A' && c <= 'Z') {
        return c - 'A' + 10;
    }
    return c - 'a' + 10;
}

// ----------------------------------------------------------------------------
// Bit String Implementation
// ----------------------------------------------------------------------------
sm2_bitstring sm2_bitstring_wrap(uint8_t *buf, uint32_t buf_size, uint32_t data_bits) {
    sm2_bitstring res = {
            .byte_len = (data_bits + 7) / 8,
            .bit_len = data_bits,
            .data_cap = buf_size,
            .data = buf
    };
    if (data_bits == 0) {
        memset(buf, 0, buf_size);
    }
    return res;
}

int sm2_bitstring_get_bit_value(const sm2_bitstring *bs, uint32_t bit_idx) {
    assert(bit_idx < bs->bit_len);
    return bs->data[bit_idx / 8] >> (7 - bit_idx % 8) & 0x01;
}

void sm2_bitstring_set_bit_value(sm2_bitstring *bs, uint32_t bit_idx, bool bit_val) {
    assert(bit_idx < bs->bit_len);
    if (bit_val) {
        bs->data[bit_idx / 8] |= 1u << (7 - bit_idx % 8);
    } else {
        bs->data[bit_idx / 8] &= ~(1u << (7 - bit_idx % 8));
    }
}

void sm2_bitstring_set_from_cstr(sm2_bitstring *res, const char *cstr) {
    const size_t cstr_len = strlen(cstr);
    assert(cstr_len <= res->data_cap);
    res->byte_len = cstr_len;
    res->bit_len = cstr_len * 8;
    for (int i = 0; i < cstr_len; ++i) {
        res->data[i] = (uint8_t) cstr[i];
    }
}

void sm2_bitstring_set_from_hex_str(sm2_bitstring *res, const char *hexstr) {
    const int str_len = (int) strlen(hexstr);
    const int byte_len = str_len / 2;
    assert(res->byte_len + byte_len <= res->data_cap);
    uint32_t byte_offset = res->byte_len;
    res->byte_len += byte_len;
    res->bit_len += byte_len * 8;
    for (int i = 0, j = 0; i < str_len; i += 2, j += 1) {
        res->data[byte_offset + j] = (uint8_t) sm2_helper_hex2i(hexstr[i]) * 16 + sm2_helper_hex2i(hexstr[i + 1]);
    }
}

void sm2_bitstring_set_from_bytes(sm2_bitstring *res, const uint8_t *bytes, uint32_t byte_len) {
    assert(res->byte_len + byte_len <= res->data_cap);
    uint32_t byte_offset = res->byte_len;
    res->byte_len += byte_len;
    res->bit_len += byte_len * 8;
    for (int i = 0; i < byte_len; ++i) {
        res->data[byte_offset + i] = bytes[i];
    }
}

void sm2_bitstring_update_from_sm2_bigint(sm2_bitstring *bs, uint64_t offset, const sm2_bigint *x) {
    for (int i = SM2_BIGINT_DATA_LEN - 1; i >= 0; --i) {
        bs->data[offset] = (x->data[i] >> 24) & 0xFF;
        bs->data[offset + 1] = (x->data[i] >> 16) & 0xFF;
        bs->data[offset + 2] = (x->data[i] >> 8) & 0xFF;
        bs->data[offset + 3] = x->data[i] & 0xFF;
        offset += 4;
    }
}


// ----------------------------------------------------------------------------
// 32 bytes Int in Field Fp
// ----------------------------------------------------------------------------
void sm2_bigint_set_from_bytes(sm2_bigint *res, const uint8_t *bytes) {
    for (int i = SM2_BIGINT_DATA_LEN - 1, j = 0; i >= 0; --i, j += 4) {
        const uint32_t s3 = bytes[j];
        const uint32_t s2 = bytes[j + 1];
        const uint32_t s1 = bytes[j + 2];
        const uint32_t s0 = bytes[j + 3];
        res->data[i] = s3 << 24 | s2 << 16 | s1 << 8 | s0;
    }
}

void sm2_bigint_set_from_hex_str(sm2_bigint *res, const char *str) {
    const int str_len = (int) strlen(str);
    assert(str_len >= 64);
    for (int i = 0, j = 7; i < 64; i += 8, j -= 1) {
        uint32_t s3 = sm2_helper_hex2i(str[i]) * 16 + sm2_helper_hex2i(str[i + 1]);
        uint32_t s2 = sm2_helper_hex2i(str[i + 2]) * 16 + sm2_helper_hex2i(str[i + 3]);
        uint32_t s1 = sm2_helper_hex2i(str[i + 4]) * 16 + sm2_helper_hex2i(str[i + 5]);
        uint32_t s0 = sm2_helper_hex2i(str[i + 6]) * 16 + sm2_helper_hex2i(str[i + 7]);
        // printf("Read %d %d %d %d\n", s3, s2, s1, s0);
        res->data[j] = ((uint32_t) s3 << 24)
                       | ((uint32_t) s2 << 16)
                       | ((uint32_t) s1 << 8)
                       | s0;
    }
}

void sm2_bigint_set_from_u32(sm2_bigint *x, uint32_t v) {
    for (int i = 0; i < SM2_BIGINT_DATA_LEN; ++i) {
        x->data[i] = 0;
    }
    x->data[0] = v;
}

void sm2_bigint_set_from_other(sm2_bigint *x, const sm2_bigint *other) {
    for (int i = 0; i < SM2_BIGINT_DATA_LEN; ++i) {
        x->data[i] = other->data[i];
    }
}

void sm2_bigint_set_from_bitstring(sm2_bigint *res, const sm2_bitstring *bs) {
    assert(bs != NULL && bs->byte_len == 32);
    for (int i = 0, j = SM2_BIGINT_DATA_LEN - 1; i < bs->byte_len && j >= 0; i += 4, --j) {
        const uint32_t b3 = bs->data[i];
        const uint32_t b2 = bs->data[i + 1];
        const uint32_t b1 = bs->data[i + 2];
        const uint32_t b0 = bs->data[i + 3];
        res->data[j] = (b3 << 24) | (b2 << 16) | (b1 << 8) | b0;
    }
}

void sm2_bigint_to_bytes(sm2_bigint *x, uint8_t *bytes) {
    if (x == NULL) return;
    for (int i = SM2_BIGINT_DATA_LEN - 1, j = 0; i >= 0; --i, j += 4) {
        bytes[j] = (x->data[i] >> 24) & 0xFF;
        bytes[j + 1] = (x->data[i] >> 16) & 0xFF;
        bytes[j + 2] = (x->data[i] >> 8) & 0xFF;
        bytes[j + 3] = x->data[i] & 0xFF;
    }
}

sm2_cmp_order sm2_bigint_cmp(const sm2_bigint *a, const sm2_bigint *b) {
    assert(a != NULL && b != NULL);
    if (a != b && a != NULL && b != NULL) {
        for (int i = SM2_BIGINT_DATA_LEN - 1; i >= 0; --i) {
            if (a->data[i] > b->data[i]) {
                return SM2_CMP_ORDER_GREATER;
            }
            if (a->data[i] < b->data[i]) {
                return SM2_CMP_ORDER_LESS;
            }
        }
    }
    return SM2_CMP_ORDER_EQUAL;
}

bool sm2_bigint_is_zero(const sm2_bigint *x) {
    assert(x != NULL);
    for (int i = 0; i < SM2_BIGINT_DATA_LEN; ++i) {
        if (x->data[i] != 0) {
            return false;
        }
    }
    return true;
}

// Bigint Internal Helpers
// Check if a bit is set
bool sm2_bigint_is_bit_set(const sm2_bigint *x, const int bit_index) {
    const int byte_idx = bit_index / SM2_BIGINT_DATA_SIZE;
    const int bit_pos = bit_index % SM2_BIGINT_DATA_SIZE;
    return x->data[byte_idx] & (1ull << bit_pos);
}
// Find the left most 1 bit
int sm2_bigint_msb(const sm2_bigint *x) {
    for (int i = SM2_BIGINT_DATA_LEN - 1; i >= 0; --i) {
        if (x->data[i] != 0) {
            for (int j = SM2_BIGINT_DATA_SIZE - 1; j >= 0; --j) {
                if (x->data[i] >> j & 1) {
                    return i * SM2_BIGINT_DATA_SIZE + j + 1;
                }
            }
        }
    }
    return 0;
}

uint64_t sm2_bigint_direct_add(sm2_bigint *t, const sm2_bigint *a, const sm2_bigint *b) {
    uint64_t carry = 0;
    for (int i = 0; i < SM2_BIGINT_DATA_LEN; ++i) {
        const uint64_t u = a->data[i];
        const uint64_t v = b->data[i];
        const uint64_t s = u + v + carry;
        t->data[i] = s & 0xFFFFFFFF;
        carry = (s >> 32) & 0xFFFFFFFF;
        // printf("x = %08X carry = %llu\n", t->data[i], carry);
    }
    return carry;
}

uint64_t sm2_bigint_direct_sub(sm2_bigint *t, const sm2_bigint *a, const sm2_bigint *b) {
    uint64_t borrow = 0;
    for (int i = 0; i < SM2_BIGINT_DATA_LEN; ++i) {
        const uint64_t u = a->data[i];
        const uint64_t v = b->data[i];
        if ((borrow == 0 || u != 0) && u - borrow >= v) {
            t->data[i] = u - v - borrow;
            borrow = 0;
        } else {
            t->data[i] = ((uint64_t) 1 << 32) + u - v - borrow;
            borrow = 1;
        }

    }
    return borrow;
}

// t = t % p
void sm2_bigint_norm(sm2_bigint *t, const sm2_bigint *p) {
    assert(t != NULL && p != NULL);
    while (sm2_bigint_cmp(t, p) == SM2_CMP_ORDER_GREATER) {
        // x -= p
        uint64_t borrow = sm2_bigint_direct_sub(t, t, p);
        assert(borrow == 0);
    }
}

// t = (a + b) % p
void sm2_bigint_add_mod_p(sm2_bigint *t, const sm2_bigint *a, const sm2_bigint *b, const sm2_bigint *p) {
    assert(t != NULL && a != NULL && b != NULL && p != NULL);
    // sm2_bigint* s = sm2_bigint_new();
    const uint64_t carry = sm2_bigint_direct_add(t, a, b);
    if (carry != 0) {
        sm2_bigint_direct_sub(t, t, p);
    }
    sm2_bigint_norm(t, p);
    // sm2_bigint_set_from_other(t, s);
    // sm2_bigint_delete(s);
}

// t = (a - b) % p
void sm2_bigint_sub_mod_p(sm2_bigint *t, const sm2_bigint *a, const sm2_bigint *b, const sm2_bigint *p) {
    assert(t != NULL && a != NULL && b != NULL && p != NULL);
    sm2_cmp_order cmp_res = sm2_bigint_cmp(a, b);
    if (cmp_res == SM2_CMP_ORDER_EQUAL) {
        sm2_bigint_set_from_u32(t, 0);
        return;
    }
    if (cmp_res == SM2_CMP_ORDER_LESS) {
        // t = (a + p - b) % p
        sm2_bigint_direct_add(t, a, p);
        sm2_bigint_direct_sub(t, t, b);
    } else {
        sm2_bigint_direct_sub(t, a, b);
    }
}

// t = (a * b) % p
// e.g b = 0b00010001
void sm2_bigint_mul_mod_p(sm2_bigint *t, const sm2_bigint *a, const sm2_bigint *b, const sm2_bigint *p) {
    assert(t != NULL && a != NULL && b != NULL && p != NULL);
    int msb_a = sm2_bigint_msb(a);
    int msb_b = sm2_bigint_msb(b);
    sm2_bigint base, res;
    sm2_bigint_set_from_u32(&res, 0);
    if (msb_a < msb_b) {
        sm2_bigint_set_from_other(&base, b);
        for (int i = 0; i < msb_a; ++i) {
            if (sm2_bigint_is_bit_set(a, i)) {
                // t += base
                sm2_bigint_add_mod_p(&res, &res, &base, p);
            }
            sm2_bigint_add_mod_p(&base, &base, &base, p);
        }
    } else {
        sm2_bigint_set_from_other(&base, a);
        for (int i = 0; i < msb_b; ++i) {
            if (sm2_bigint_is_bit_set(b, i)) {
                // t += base
                sm2_bigint_add_mod_p(&res, &res, &base, p);
            }
            sm2_bigint_add_mod_p(&base, &base, &base, p);
        }
    }
    sm2_bigint_set_from_other(t, &res);
}

// t = (a^b) % p
void sm2_bigint_pow_mod_p(sm2_bigint *t, const sm2_bigint *a, const sm2_bigint *b, const sm2_bigint *p) {
    int msb_b = sm2_bigint_msb(b);
    sm2_bigint base, res;
    sm2_bigint_set_from_other(&base, a);
    sm2_bigint_set_from_u32(&res, 1);
    for (int i = 0; i < msb_b; ++i) {
        if (sm2_bigint_is_bit_set(b, i)) {
            sm2_bigint_mul_mod_p(&res, &res, &base, p);
        }
        sm2_bigint_mul_mod_p(&base, &base, &base, p);
    }
    sm2_bigint_set_from_other(t, &res);
}

void sm2_bigint_inv_mod_p(sm2_bigint *t, const sm2_bigint *a, const sm2_bigint *p) {
    sm2_bigint q;
    sm2_bigint two;
    sm2_bigint_set_from_u32(&q, 0);
    sm2_bigint_set_from_u32(&two, 2);
    sm2_bigint_sub_mod_p(&q, p, &two, p);
    // a^(p-2)
    sm2_bigint_pow_mod_p(t, a, &q, p);
    // give other tasks some time to run
    sm2_yield_cpu();
}

// ----------------------------------------------------------------------------
// SM2 Default Functions
// ----------------------------------------------------------------------------
/**
 * Random bigint integer k generation, used in sign process and data encryption.
 * @param ctx the ctx object used
 */
void sm2_internal_change_k(sm2_ctx *ctx) {
    // 1 <= k <= n - 1
    do {
        for (int i = 0; i < SM2_BIGINT_DATA_LEN; i++) {
            uint32_t high_byte = (uint32_t) rand();
            uint32_t low_byte = (uint32_t) rand();
            ctx->k.data[i] = (high_byte << 16) | (low_byte & 0xFFFF);
        }
        sm2_bigint_norm(&ctx->k, &ctx->n);
    } while (sm2_bigint_is_zero(&ctx->k));
}
// SM2 hash from at most 3 sm2_bitstring.
void sm2_internal_hash(
        uint8_t hash_result[SM2_HASH_RESULT_BYTES],
        const uint8_t *s1, uint32_t s1_bits,
        const uint8_t *s2, uint32_t s2_bits,
        const uint8_t *s3, uint32_t s3_bits
) {
    sm3_ctx_t ctx;
    uint8_t hash_buf[SM2_HASH_BUFFER_BYTES]; // buf = 512 bits = 64 bytes
    sm3_stream_start(&ctx);
    // Byte Mode
    if (s1_bits % 8 == 0 && s2_bits % 8 == 0 && s3_bits % 8 == 0) {
        uint32_t s1_bytes = s1_bits / 8;
        uint32_t s2_bytes = s2_bits / 8;
        uint32_t s3_bytes = s3_bits / 8;
        uint32_t total_bytes = s1_bytes + s2_bytes + s3_bytes;
        for (uint32_t i = 0; i < total_bytes; i += SM2_HASH_BUFFER_BYTES) {
            uint32_t active_bytes = SM2_HASH_BUFFER_BYTES;
            if ((total_bytes - i) < active_bytes) {
                active_bytes = total_bytes - i;
            }
            for (int j = 0; j < SM2_HASH_BUFFER_BYTES; ++j) {
                if (i + j < s1_bytes) {
                    hash_buf[j] = s1[i + j];
                } else if (i + j < s1_bytes + s2_bytes) {
                    hash_buf[j] = s2[i - s1_bytes + j];
                } else if (i + j < s1_bytes + s2_bytes + s3_bytes) {
                    hash_buf[j] = s3[i - s1_bytes - s2_bytes + j];
                } else {
                    hash_buf[j] = 0;
                }
            }
            sm3_stream_update(&ctx, hash_buf, active_bytes * 8);
        }
    } else {
        // Bit Mode
        uint32_t total_bits = s1_bits + s2_bits + s3_bits;
        for (uint32_t i = 0; i < total_bits; i += SM2_HASH_BUFFER_BITS) {
            memset(hash_buf, 0, SM2_HASH_BUFFER_BYTES);
            uint32_t active_bits = SM2_HASH_BUFFER_BITS;
            if ((total_bits - i) < active_bits) {
                active_bits = total_bits - i;
            }
            for (int j = 0; j < SM2_HASH_BUFFER_BITS; ++j) {
                int bit_val = 0;
                if (i + j < s1_bits) {
                    bit_val = s1[(i + j) / 8] >> (7 - (i + j) % 8) & 0x01;
                } else if (i + j < s1_bits + s2_bits) {
                    bit_val = s1[(i + j - s1_bits) / 8] >> (7 - (i + j - s1_bits) % 8) & 0x01;
                } else if (i + j < s1_bits + s2_bits + s3_bits) {
                    bit_val = s1[(i + j - s1_bits - s2_bits) / 8] >> (7 - (i + j - s1_bits - s2_bits) % 8) & 0x01;
                } else {
                    break;
                }
                if (bit_val) {
                    hash_buf[j / 8] |= bit_val << (7 - j % 8);
                }
            }
            sm3_stream_update(&ctx, hash_buf, active_bits);
        }
    }
    sm3_stream_finish(&ctx, hash_result);
    sm2_yield_cpu();
}

// Key Derived Function
void sm2_internal_kdf(
        const uint8_t *zstr,
        uint32_t zbits,
        uint8_t *kstr,
        uint32_t kbits
) {
    uint8_t counter[4] = {0x00, 0x00, 0x00, 0x01};
    uint8_t hash_res[32]; // 256 bits
    uint32_t g_cnt = (kbits + SM2_HASH_RESULT_BITS - 1) / SM2_HASH_RESULT_BITS;
    for (uint32_t g = 1, kstr_base = 0; g <= g_cnt; ++g, kstr_base += 32) {
        // hash_res = Hash256(Z||counter)
        sm2_internal_hash(hash_res, zstr, zbits, counter, 32, NULL, 0);
        // Use only kbits % hash_bits
        if (g == g_cnt && kbits % SM2_HASH_RESULT_BITS != 0) {
            // int last = kbits % hash_bits;
            for (int bit = 0; bit < kbits % SM2_HASH_RESULT_BITS; ++bit) {
                if (bit % 8 == 0) {
                    kstr[kstr_base + bit / 8] = 0;
                }
                if ((hash_res[bit / 8] >> (7 - bit % 8) & 0x01) == 0) {
                    continue;
                }
                kstr[kstr_base + bit / 8] |= 1 << (7 - bit % 8);
            }
        } else {
            for (int i = 0; i < 32; ++i) {
                kstr[kstr_base + i] = hash_res[i];
            }
        }
        // counter += 1
        for (int i = 3; i >= 0; --i) {
            if (counter[i] != 0xFF) {
                counter[i] += 1;
                break;
            }
            counter[i] = 0;
        }
    }
    sm2_yield_cpu();
}

// ----------------------------------------------------------------------------
// SM2 Context Management
// ----------------------------------------------------------------------------
void sm2_ctx_init(sm2_ctx *ctx) {
    sm2_bigint_set_from_hex_str(&ctx->p, "FFFFFFFEFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF00000000FFFFFFFFFFFFFFFF");
    sm2_bigint_set_from_hex_str(&ctx->a, "FFFFFFFEFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF00000000FFFFFFFFFFFFFFFC");
    sm2_bigint_set_from_hex_str(&ctx->b, "28E9FA9E9D9F5E344D5A9E4BCF6509A7F39789F515AB8F92DDBCBD414D940E93");
    sm2_bigint_set_from_hex_str(&ctx->n, "FFFFFFFEFFFFFFFFFFFFFFFFFFFFFFFF7203DF6B21C6052B53BBF40939D54123");
    sm2_bigint_set_from_hex_str(&ctx->Gx, "32C4AE2C1F1981195F9904466A39C9948FE30BBFF2660BE1715A4589334C74C7");
    sm2_bigint_set_from_hex_str(&ctx->Gy, "BC3736A2F4F6779C59BDCEE36B692153D0A9877CC62A474002DF32E52139F0A0");
    sm2_bigint_set_from_u32(&ctx->Px, 0);
    sm2_bigint_set_from_u32(&ctx->Py, 0);
    sm2_bigint_set_from_u32(&ctx->d,  0);
    sm2_bigint_set_from_u32(&ctx->k,  0);
    ctx->sm2_change_k = sm2_internal_change_k;
}

void sm2_ctx_set_public_key(sm2_ctx *ctx, const char *public_key) {
    sm2_bigint_set_from_hex_str(&ctx->Px, public_key);
    sm2_bigint_set_from_hex_str(&ctx->Py, public_key + 64);
}

void sm2_ctx_set_private_key(sm2_ctx *ctx, const char *private_key) {
    sm2_bigint_set_from_hex_str(&ctx->d, private_key);
}

void sm2_build_zstr(const sm2_ctx *ctx, sm2_bitstring *res, const sm2_bitstring *user_id) {
    uint16_t entlen_a = user_id->byte_len;
    uint32_t total_bytes = 2 + entlen_a + SM2_BIGINT_DATA_BYTES * 6;
    res->data[0] = (entlen_a >> 5) & 0xFF;
    res->data[1] = (entlen_a << 3) & 0xFF;
    uint32_t offset = 2;
    memcpy(res->data + offset, user_id->data, user_id->byte_len);
    offset += user_id->byte_len;
    sm2_bitstring_update_from_sm2_bigint(res, offset, &ctx->a);
    offset += SM2_BIGINT_DATA_BYTES;
    sm2_bitstring_update_from_sm2_bigint(res, offset, &ctx->b);
    offset += SM2_BIGINT_DATA_BYTES;
    sm2_bitstring_update_from_sm2_bigint(res, offset, &ctx->Gx);
    offset += SM2_BIGINT_DATA_BYTES;
    sm2_bitstring_update_from_sm2_bigint(res, offset, &ctx->Gy);
    offset += SM2_BIGINT_DATA_BYTES;
    sm2_bitstring_update_from_sm2_bigint(res, offset, &ctx->Px);
    offset += SM2_BIGINT_DATA_BYTES;
    sm2_bitstring_update_from_sm2_bigint(res, offset, &ctx->Py);
    res->byte_len = total_bytes;
    res->bit_len = total_bytes * 8;
}

// ----------------------------------------------------------------------------
// Encode SM2 Signature to DER
//
//  SEQUENCE Byte = 0x30
//  | 8 7 | 6 | 5 4 3 2 1 |
//    0 0   1   1 0 0 0 0
//   ASN.1  C   SEQUENCE
//
//  length byte
//  | 8 | 7 6 5 4 3 2 1 |
//    0  0-127 bytes
//    1  length = 1-126 following bytes
//
//  INTEGER Byte = 0x02
//  * for 256bit int => |0x02|0x20|...256bits...|
//  | 8 7 | 6 | 5 4 3 2 1 |
//    0 0   0   0 0 0 1 0
//   ASN.1  P   INTEGER
//
//  For our 256bits INTEGER => length byte => 0x20
//  |0x30|0x44|INT_R|INT_S|
void sm2_signature_to_der(uint8_t *result, const sm2_signature *signature) {
    // 2 + 34 + 34
    result[0] = 0x30;
    result[1] = 0x44;
    result[2] = 0x02;
    result[3] = 0x20;
    memcpy(result + 4, signature->r, 32);
    result[36] = 0x02;
    result[37] = 0x20;
    memcpy(result + 38, signature->s, 32);
}

// ----------------------------------------------------------------------------
// SM2 ECC (Implement in the Projective Coordinate System)
// ECC Func: Y^2 * z = X^3 + a * X * z^2 + b * z^3
// proj <x, y, z> => std <x/z, y/z, 1>
// ----------------------------------------------------------------------------

void sm2_ecc_point_set_zero(sm2_ecc_point *p) {
    sm2_bigint_set_from_u32(&p->x, 0);
    sm2_bigint_set_from_u32(&p->y, 1);
    sm2_bigint_set_from_u32(&p->z, 0);
}

void sm2_ecc_point_set_xy(sm2_ecc_point *p, const sm2_bigint *x, const sm2_bigint *y) {
    sm2_bigint_set_from_other(&p->x, x);
    sm2_bigint_set_from_other(&p->y, y);
    sm2_bigint_set_from_u32(&p->z, 1);
}

void sm2_ecc_point_set_from_other(sm2_ecc_point *p, const sm2_ecc_point *other) {
    sm2_bigint_set_from_other(&p->x, &other->x);
    sm2_bigint_set_from_other(&p->y, &other->y);
    sm2_bigint_set_from_other(&p->z, &other->z);
}

void sm2_ecc_point_norm(const sm2_ctx *ctx, sm2_ecc_point *p) {
    if (sm2_bigint_is_zero(&p->z)) {
        sm2_ecc_point_set_zero(p);
    } else {
        // <x, y, z> => <x/z, y/z, 1>
        sm2_bigint inv_z;
        sm2_bigint_inv_mod_p(&inv_z, &p->z, &ctx->p);
        sm2_bigint_mul_mod_p(&p->x, &p->x, &inv_z, &ctx->p);
        sm2_bigint_mul_mod_p(&p->y, &p->y, &inv_z, &ctx->p);
        sm2_bigint_set_from_u32(&p->z, 1);
    }
}

bool sm2_ecc_point_is_same(const sm2_ctx *ctx, const sm2_ecc_point *A, const sm2_ecc_point *B) {
    bool Az_zero = sm2_bigint_is_zero(&A->z);
    bool Bz_zero = sm2_bigint_is_zero(&B->z);
    if (Az_zero && Bz_zero) {
        return true;
    }
    if (Az_zero || Bz_zero) {
        return false;
    }
    // Ax * Bz = Bx * Az
    // Ay * Bz = By * Az
    sm2_bigint vl, vr;
    sm2_bigint_mul_mod_p(&vl, &A->x, &B->z, &ctx->p);
    sm2_bigint_mul_mod_p(&vr, &B->x, &A->z, &ctx->p);
    if (sm2_bigint_cmp(&vl, &vr) != SM2_CMP_ORDER_EQUAL) {
        return false;
    }
    sm2_bigint_mul_mod_p(&vl, &A->y, &B->z, &ctx->p);
    sm2_bigint_mul_mod_p(&vr, &B->y, &A->z, &ctx->p);
    if (sm2_bigint_cmp(&vl, &vr) != SM2_CMP_ORDER_EQUAL) {
        return false;
    }
    return true;
}

void sm2_ecc_point_add(
    const sm2_ctx *ctx,
    sm2_ecc_point *result,
    const sm2_ecc_point *p1,
    const sm2_ecc_point *p2
) {
    sm2_bigint v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, t0;
    const sm2_bigint *p = &ctx->p;
    sm2_ecc_point res;
    // O + O == O
    bool p1z_is_zero = sm2_bigint_is_zero(&p1->z);
    bool p2z_is_zero = sm2_bigint_is_zero(&p2->z);
    if (p1z_is_zero && p2z_is_zero) {
        sm2_ecc_point_set_zero(result);
        return;
    }
    // P + O == P
    if (p1z_is_zero) {
        sm2_ecc_point_set_from_other(result, p2);
        return;
    }
    if (p2z_is_zero) {
        sm2_ecc_point_set_from_other(result, p1);
        return;
    }
    // p1 + p2 = 0
    // <x,y,z> + <ux, p-uy, uz> = 0
    sm2_ecc_point p1_inv;
    sm2_ecc_point_set_from_other(&p1_inv, p1);
    sm2_bigint_sub_mod_p(&p1_inv.y, &ctx->p, &p1_inv.y, p);
    if (sm2_ecc_point_is_same(ctx, &p1_inv, p2)) {
        sm2_ecc_point_set_zero(result);
        return;
    }
    // p1 = p2
    if (sm2_ecc_point_is_same(ctx, p1, p2)) {
        // v1 = 3x^2 + a z1^2
        sm2_bigint_mul_mod_p(&v1, &p1->x, &p1->x, p);
        sm2_bigint_set_from_u32(&t0, 3);
        sm2_bigint_mul_mod_p(&v1, &v1, &t0, p);       // v1 = 3x^2
        sm2_bigint_mul_mod_p(&t0, &p1->z, &p1->z, p); // t0 = z^2
        sm2_bigint_mul_mod_p(&t0, &t0, &ctx->a, p);   // t0 *= a
        sm2_bigint_add_mod_p(&v1, &v1, &t0, p);       // v1 += a*z^2
        // v2 = 2yz
        sm2_bigint_mul_mod_p(&t0, &p1->y, &p1->z, p);
        sm2_bigint_add_mod_p(&v2, &t0, &t0, p);
        // v3 = y1^2
        sm2_bigint_mul_mod_p(&v3, &p1->y, &p1->y, p);
        // v4 = v3 xz
        sm2_bigint_mul_mod_p(&t0, &p1->x, &p1->z, p);
        sm2_bigint_mul_mod_p(&v4, &v3, &t0, p);
        // v5 = v2^2
        sm2_bigint_mul_mod_p(&v5, &v2, &v2, p);
        // v6 = v1^2 - 8v4
        sm2_bigint_mul_mod_p(&v6, &v1, &v1, p);
        sm2_bigint_set_from_u32(&t0, 8);
        sm2_bigint_mul_mod_p(&t0, &v4, &t0, p);
        sm2_bigint_sub_mod_p(&v6, &v6, &t0, p);
        // x3 = v2 * v6
        sm2_bigint_mul_mod_p(&res.x, &v2, &v6, p);
        // y3 = v1*(4 * v4 - v6) - 2 * v5 * v3;
        sm2_bigint_set_from_u32(&t0, 4);
        sm2_bigint_mul_mod_p(&res.y, &t0, &v4, p);     // y = 4 * v4
        sm2_bigint_sub_mod_p(&res.y, &res.y, &v6, p);  // y = 4 * v4 - v6
        sm2_bigint_mul_mod_p(&res.y, &res.y, &v1, p);  // y *= v1
        sm2_bigint_mul_mod_p(&t0, &v5, &v3, p);
        sm2_bigint_add_mod_p(&t0, &t0, &t0, p);        // t1 = 2 * v5 * v3
        sm2_bigint_sub_mod_p(&res.y, &res.y, &t0, p);  // y -= t1
        // z3 = v2 * v5
        sm2_bigint_mul_mod_p(&res.z, &v2, &v5, p);
    } else {
        // p1 != p2
        // v1 = x1 * z2
        sm2_bigint_mul_mod_p(&v1, &p1->x, &p2->z, p);
        // v2 = x2 * z1
        sm2_bigint_mul_mod_p(&v2, &p2->x, &p1->z, p);
        // v3 = v1 - v2
        sm2_bigint_sub_mod_p(&v3, &v1, &v2, p);
        // v4 = y1 * z2
        sm2_bigint_mul_mod_p(&v4, &p1->y, &p2->z, p);
        // v5 = y2 * z1
        sm2_bigint_mul_mod_p(&v5, &p2->y, &p1->z, p);
        // v6 = v4 - v5
        sm2_bigint_sub_mod_p(&v6, &v4, &v5, p);
        // v7 = v1 + v2
        sm2_bigint_add_mod_p(&v7, &v1, &v2, p);
        // v8 = z1 * z2
        sm2_bigint_mul_mod_p(&v8, &p1->z, &p2->z, p);
        // v9 = v3 * v3
        sm2_bigint_mul_mod_p(&v9, &v3, &v3, p);
        // v10 = v3 * v9
        sm2_bigint_mul_mod_p(&v10, &v3, &v9, p);
        // v11 = v8 * v6 * v6 - v7 * v9
        sm2_bigint_mul_mod_p(&v11, &v8, &v6, p);
        sm2_bigint_mul_mod_p(&v11, &v11, &v6, p);
        sm2_bigint_mul_mod_p(&t0, &v7, &v9, p);
        sm2_bigint_sub_mod_p(&v11, &v11, &t0, p);
        // x3 = v3 * v11
        sm2_bigint_mul_mod_p(&res.x, &v3, &v11, p);
        // y3 = v6(v9 * v1 - v11) - v4 * v10
        sm2_bigint_mul_mod_p(&t0, &v9, &v1, p);
        sm2_bigint_sub_mod_p(&t0, &t0, &v11, p); // t0 = v9 * v1 - v11
        sm2_bigint_mul_mod_p(&res.y, &v6, &t0, p);
        sm2_bigint_mul_mod_p(&t0, &v4, &v10, p);
        sm2_bigint_sub_mod_p(&res.y, &res.y, &t0, p);
        // z3 = v10 * v8
        sm2_bigint_mul_mod_p(&res.z, &v10, &v8, p);
    }
    // fill result
    sm2_ecc_point_set_from_other(result, &res);
}

// ============================================================================
// [k](Px, Py, Pz)
void sm2_ecc_point_mul_k(
    const sm2_ctx *ctx,
    sm2_ecc_point *res,
    const sm2_ecc_point *p,
    const sm2_bigint *k
) {
    int msb = sm2_bigint_msb(k);
    sm2_ecc_point_set_zero(res);
    sm2_ecc_point base;
    sm2_ecc_point_set_from_other(&base, p);
    for (int i = 0; i < msb; i++) {
        sm2_yield_cpu();
        if (sm2_bigint_is_bit_set(k, i)) {
            // res = res + base
            sm2_ecc_point_add(ctx, res, res, &base);
        }
        // base = base + base
        sm2_ecc_point_add(ctx, &base, &base, &base);
    }
    sm2_yield_cpu();
    sm2_ecc_point_norm(ctx, res);
}

// ============================================================================
// SM2 Digital Signature Generate & Verify Impl
// ============================================================================
// Create the digest of za and message.
void sm2_build_digest(sm2_bitstring *digest, const sm2_bitstring* za, const sm2_bitstring* message) {
	sm2_internal_hash(
		digest->data,
		za->data,
		za->bit_len,
		message->data,
		message->bit_len,
		NULL,
		0
	);
	digest->byte_len = 32;
	digest->bit_len = 256;

}
int sm2_sign_generate(const sm2_ctx *ctx, const sm2_bitstring *digest, sm2_signature *signature) {
    // e = H256(ZA||M)
    sm2_bigint e;
    sm2_bigint_set_from_bitstring(&e, digest);

    printf("@ Try k = ");
    sm2_show_bigint(&ctx->k);

    // Solve ECC
    printf("  - ECC Calculate [k]G, may take a while.\n");
    // point (x1, y1) = [k]G
    sm2_ecc_point G;
    sm2_ecc_point kG;
    sm2_ecc_point_set_xy(&G, &ctx->Gx, &ctx->Gy);
    sm2_ecc_point_mul_k(ctx, &kG, &G, &ctx->k);
    // show_sm2_ecc_point("kG", &kG);
    // printf("Solved, generate <r,s>\n");
    sm2_bigint x1, y1, r, s, t0, t1, one;

    // sm2_bigint kGx, kGy;
    sm2_bigint_set_from_other(&x1, &kG.x);
    sm2_bigint_set_from_other(&y1, &kG.y);
    sm2_bigint_set_from_u32(&r, 0);
    sm2_bigint_set_from_u32(&s, 0);
    sm2_bigint_set_from_u32(&t0, 0);
    sm2_bigint_set_from_u32(&t1, 0);
    sm2_bigint_set_from_u32(&one, 1);

    printf("  - Calculate <r,s>\n");
    // calculate r = (e + x1) mod n
    const sm2_bigint *n = &ctx->n;
    sm2_bigint_norm(&e, n);
    sm2_bigint_norm(&x1, n);
    sm2_bigint_norm(&y1, n);
    sm2_bigint_add_mod_p(&r, &e, &x1, n);
    sm2_bigint_add_mod_p(&s, &r, &ctx->k, n);
    if (sm2_bigint_is_zero(&r) || sm2_bigint_is_zero(&s)) {
        // r failed, try again with another k
        printf("[SM2 generate] r generate failed, try another k\n");
        return -22001;
    }
    sm2_yield_cpu();
    // t1 = (1 + da)^-1
    sm2_bigint_add_mod_p(&t0, &ctx->d, &one, n);
    sm2_bigint_inv_mod_p(&t1, &t0, n);
    // t0 = k - r x da
    sm2_bigint_mul_mod_p(&t0, &r, &ctx->d, n);
    sm2_bigint_sub_mod_p(&t0, &ctx->k, &t0, n);
    // s = (t0 x t1) mod n
    sm2_bigint_mul_mod_p(&s, &t0, &t1, n);
    if (sm2_bigint_is_zero(&s)) {
        // s failed, try again with another k
        printf("[SM2 generate] s generate failed, try another k\n");
        return -22002;
    }
    sm2_bigint_to_bytes(&r, signature->r);
    sm2_bigint_to_bytes(&s, signature->s);
    // sm2_show_signature(signature);
    return 0;
}

int sm2_sign_verify(const sm2_ctx *ctx, const sm2_bitstring *digest, const sm2_signature *signature) {
    sm2_bigint r;
    sm2_bigint_set_from_bytes(&r, (uint8_t *) &signature->r);
    const bool r_is_zero = sm2_bigint_is_zero(&r);
    const sm2_cmp_order r_cmp_n = sm2_bigint_cmp(&r, &ctx->n);
    if (r_is_zero || r_cmp_n != SM2_CMP_ORDER_LESS) {
        printf("[SM2 verify] invalid r: out of range\n");
        return -22003;
    }
    sm2_bigint s;
    sm2_bigint_set_from_bytes(&s, (uint8_t *) &signature->s);
    const bool s_is_zero = sm2_bigint_is_zero(&s);
    const sm2_cmp_order s_cmp_n = sm2_bigint_cmp(&s, &ctx->n);
    if (s_is_zero || s_cmp_n != SM2_CMP_ORDER_LESS) {
        printf("[SM2 verify] invalid s: out of range\n");
        return -22004;
    }
    sm2_bigint t;
    sm2_bigint_add_mod_p(&t, &r, &s, &ctx->n);
    if (sm2_bigint_is_zero(&t)) {
        printf("[SM2 verify] invalid (r, s) pair: r + s = 0\n");
        return -22005;
    }
    // Find point in ECC
    sm2_ecc_point R, G, P, sG, tP;
    sm2_ecc_point_set_zero(&R);

    printf("  - ECC Calculate: R = [s]G + [t]P, may take a while ...\n");
    // (Rx, Ry) = [s](Gx, Gy) + [t](Px, Py)
    sm2_ecc_point_set_xy(&G, &ctx->Gx, &ctx->Gy);
    sm2_ecc_point_set_xy(&P, &ctx->Px, &ctx->Py);
    sm2_ecc_point_mul_k(ctx, &sG, &G, &s);
    sm2_ecc_point_mul_k(ctx, &tP, &P, &t);
    // R = sG + tP
    sm2_ecc_point_add(ctx, &R, &sG, &tP);
    sm2_yield_cpu();
    sm2_ecc_point_norm(ctx, &R);
    // show_sm2_ecc_point("sG", sG);
    // show_sm2_ecc_point("tP", tP);
    // show_sm2_ecc_point("(sG + tP)", R);
    // e = H(256)(Za||M)
    sm2_bigint e;
    sm2_bigint_set_from_bitstring(&e, digest);
    // printf("* e'\n");
    // show_sm2_bigint(e);
    sm2_bigint_add_mod_p(&e, &e, &R.x, &ctx->n);
    printf("  - Check if r = (e + R.x) mod n'\n");
    // show_sm2_bigint(e);
    if (sm2_bigint_cmp(&e, &r) != SM2_CMP_ORDER_EQUAL) {
        printf("[SM2 verify] invalid (r, s) pair: r != (e + R.x)\n");
        return -22006;
    }
    return 0;
}

// ============================================================================
// SM2 Data Encryption & Decryption Impl
// ============================================================================
// SM2 Encryption (C1|C3|C2 Format)
int sm2_data_encrypt(const sm2_ctx *ctx, const sm2_bitstring *plain_msg, sm2_bitstring *encrypted_msg) {
    uint32_t klen = plain_msg->bit_len;
    assert(encrypted_msg->data_cap >= (783 + klen) / 8);

    printf("@ Encrypting Data C1||C3||C2 ...\n  - k = ");
    sm2_show_bigint(&ctx->k);

    // A2. Calculate kG = (x1, y1)
    printf("  - ECC Calculate [k]G, may take a while.\n");
    sm2_ecc_point G;
    sm2_ecc_point kG;
    sm2_ecc_point_set_xy(&G, &ctx->Gx, &ctx->Gy);
    sm2_ecc_point_mul_k(ctx, &kG, &G, &ctx->k);
    // show_sm2_ecc_point("  - [k]G", &kG);

    // C1 = 0x04 || x1 || y1
    encrypted_msg->data[0] = 0x04;
    sm2_bigint_to_bytes(&kG.x, encrypted_msg->data + 1);
    sm2_bigint_to_bytes(&kG.y, encrypted_msg->data + 1 + 32);

    // A3. Calculate S=[h]Pub, h=1 in SM2
    // A4. Calculate kP = (x2, y1)
    printf("  - ECC Calculate [k]P, may take a while.\n");
    sm2_ecc_point P;
    sm2_ecc_point kP;
    sm2_ecc_point_set_xy(&P, &ctx->Px, &ctx->Py);
    sm2_ecc_point_mul_k(ctx, &kP, &P, &ctx->k);
    // show_sm2_ecc_point("  - [k]P", &kP);

    // A5. Calculate t = KDF (x2 ∥ y2, klen)
    printf("  - Calculate t = KDF (x2 ∥ y2, klen)\n");
    uint8_t x2y2[64];
    sm2_bigint_to_bytes(&kP.x, x2y2);
    sm2_bigint_to_bytes(&kP.y, x2y2 + 32);
    // stored t to C3
    sm2_internal_kdf(x2y2, 512, encrypted_msg->data + 97, klen);

    // A6. C2 = M ^ t
    bool all_zero = true;
    for (int i = 0; i < plain_msg->byte_len; ++i) {
        uint8_t t = encrypted_msg->data[97 + i];
        if (t != 0) {
            all_zero = false;
        }
        encrypted_msg->data[97 + i] = plain_msg->data[i] ^ t;
    }
    if (all_zero) {
        printf("* [Encrypt] Failed: KDF(x2y2, klen) => 0, try another K.\n");
        return -1000;
    }

    // A7. C3 = Hash256(x2 ∥ M ∥ y2)；
    printf("  - Calculate C3 = Hash256(x2 ∥ M ∥ y2)\n");
    uint8_t c3[SM2_HASH_RESULT_BYTES];
    sm2_internal_hash(
        c3,
        x2y2, 256,
        plain_msg->data, plain_msg->bit_len,
        x2y2 + 32, 256
    );
    printf("  - C3 = ");
    sm2_show_bytes(c3, SM2_HASH_RESULT_BYTES, SM2_SHOW_BYTE_WITH_SPACE);
    // A8. C = C1 || C3 || C2 => 65 bytes | 32 bytes | klen
    encrypted_msg->bit_len = 97 * 8 + plain_msg->bit_len;
    encrypted_msg->byte_len = (encrypted_msg->bit_len + 7) / 8;
    for (int i = 0; i < SM2_HASH_RESULT_BYTES; ++i) {
        encrypted_msg->data[65 + i] = c3[i];
    }
    // A9: Encrypt Succeed.
    return 0;
}

// SM2 Decrypt
int sm2_data_decrypt(const sm2_ctx *ctx, const sm2_bitstring *encrypted_msg, sm2_bitstring *plain_msg) {
    if (encrypted_msg->data[0] != 0x04) {
        printf("* [Decrypt] Failed: Invalid point format.\n");
        return -1000;
    }
    uint32_t klen = encrypted_msg->bit_len - 776;
    printf("@ Decrypting Data C1||C3||C2, message len = %lu bits...\n", klen);
    sm2_bigint cx;
    sm2_bigint cy;
    uint8_t x2y2[64];
    sm2_bigint_set_from_bytes(&cx, encrypted_msg->data + 1);
    sm2_bigint_set_from_bytes(&cy, encrypted_msg->data + 33);
    // B1: Check if C1(x1, y1) satisfied for the curve y^2 = x^3 + ax + b
    sm2_bigint lhs;
    sm2_bigint_mul_mod_p(&lhs, &cy, &cy, &ctx->p);
    sm2_bigint rhs;
    sm2_bigint_mul_mod_p(&rhs, &cx, &cx, &ctx->p);
    sm2_bigint_mul_mod_p(&rhs, &rhs, &cx, &ctx->p);
    sm2_bigint ax;
    sm2_bigint_mul_mod_p(&ax, &ctx->a, &cx, &ctx->p);
    sm2_bigint_add_mod_p(&rhs, &rhs, &ax, &ctx->p);
    sm2_bigint_add_mod_p(&rhs, &rhs, &ctx->b, &ctx->p);
    if (sm2_bigint_cmp(&lhs, &rhs) != SM2_CMP_ORDER_EQUAL) {
        printf("* [Decrypt] Failed: C1 not fit the ECC curve.\n");
        return -1001;
    }
    sm2_yield_cpu();
    // B2: S=[h]C1 ignored
    // B3: [d]C1 = (x2,y2)
    // and make sure <x1,y1> not the O point
    printf("  - ECC Calculate [d]C1, may take a while.\n");
    sm2_ecc_point C, dC;
    sm2_ecc_point_set_xy(&C, &cx, &cy);
    sm2_ecc_point_mul_k(ctx, &dC, &C, &ctx->d);
    // show_sm2_ecc_point("  - C1", &C);
    // show_sm2_ecc_point("  - [d]C1", &dC);
    sm2_bigint_to_bytes(&dC.x, x2y2);
    sm2_bigint_to_bytes(&dC.y, x2y2 + 32);
    plain_msg->bit_len = klen;
    plain_msg->byte_len = (klen + 7) / 8;
    assert(plain_msg->byte_len <= plain_msg->data_cap);
    // B4: t = KDF(x2y2, klen)
    printf("  - Calculate t = KDF (x2 ∥ y2, klen)\n");
    sm2_internal_kdf(x2y2, 512, plain_msg->data, klen);
    // B5: M = C2 ^ t
    bool all_zero = true;
    for (uint64_t i = 0; i < plain_msg->byte_len; ++i) {
        if (plain_msg->data[i] != 0) {
            all_zero = false;
        }
        plain_msg->data[i] ^= encrypted_msg->data[97 + i];
    }
    if (all_zero) {
        printf("* [Decrypt] Failed: KDF(x2y2, klen) => 0\n");
        return -1002;
    }
    // B6: tC3 = Hash256(x2 || M || y2)
    printf("  - Calculate C3 = Hash256(x2 ∥ M ∥ y2)\n");
    uint8_t tC3[SM2_HASH_RESULT_BYTES];
    sm2_internal_hash(
        tC3,
        x2y2, 256,
        plain_msg->data, plain_msg->bit_len,
        x2y2 + 32, 256
    );
    printf("  - C3 = ");
    sm2_show_bytes(tC3, SM2_HASH_RESULT_BYTES, SM2_SHOW_BYTE_WITH_SPACE);

    // check if C3 == tC3
    for (int i = 0; i < SM2_HASH_RESULT_BYTES; ++i) {
        if (encrypted_msg->data[65 + i] != tC3[i]) {
            printf("* [Decrypt] Failed: C3 not match\n");
            return -1003;
        }
    }
    // B7: Decrypt Succeed.
    return 0;
}

// -----------------------------------------------------------------------------
// Debug interfaces (with sm2_show & sm2_write prefix)
// -----------------------------------------------------------------------------
// Print to std output
void sm2_show_bytes(const uint8_t *bytes, uint32_t byte_len, bool with_space) {
    for (uint64_t i = 0; i < byte_len; ++i) {
        if (i > 0 && i % 32 == 0) {
            printf("\n");
        }
        printf("%02X", bytes[i]);
        if (i % 4 == 3 && with_space) {
            printf(" ");
        }
    }
    printf("\n");
}
void sm2_show_words(const uint32_t *words, uint64_t word_len) {
    for (uint64_t i = 0; i < word_len; ++i) {
        if (i > 0 && i % 8 == 0) {
            printf("\n");
        }
        printf("%08X ", (unsigned int) words[i]);
    }
    printf("\n");
}

void sm2_show_bitstring(const sm2_bitstring *bs) {
    if (bs == NULL) return;
    sm2_show_bytes(bs->data, bs->byte_len, SM2_SHOW_BYTE_WITH_SPACE);
}
void sm2_show_bigint(const sm2_bigint *x) {
    if (x == NULL) return;
    for (int i = SM2_BIGINT_DATA_LEN - 1; i >= 0; --i) {
        printf("%08X%s", (unsigned int) x->data[i], SM2_SHOW_BYTE_WITH_SPACE ? " " : "");
    }
    printf("\n");
}

void sm2_show_ecc_point(const char *point_name, const sm2_ecc_point *p) {
    printf("%s.x = ", point_name);
    sm2_show_bigint(&p->x);
    printf("%s.y = ", point_name);
    sm2_show_bigint(&p->y);
    printf("%s.z = ", point_name);
    sm2_show_bigint(&p->z);
}
void sm2_show_signature(const sm2_signature *signature) {
    if (signature != NULL) {
        printf("  - Signature.r = ");
        sm2_show_bytes(signature->r, 32, false);
        printf("  - Signature.s = ");
        sm2_show_bytes(signature->s, 32, false);
    }
}
void sm2_show_ctx(const sm2_ctx *ctx) {
    printf("============================");
    printf(" SM2 Context ");
    printf("=============================\n");
    printf("  p = ");
    sm2_show_bigint(&ctx->p);
    printf("  a = ");
    sm2_show_bigint(&ctx->a);
    printf("  b = ");
    sm2_show_bigint(&ctx->b);
    printf("  n = ");
    sm2_show_bigint(&ctx->n);
    printf("G.x = ");
    sm2_show_bigint(&ctx->Gx);
    printf("G.y = ");
    sm2_show_bigint(&ctx->Gy);
    printf("P.x = ");
    sm2_show_bigint(&ctx->Px);
    printf("P.y = ");
    sm2_show_bigint(&ctx->Py);
    printf("  d = ");
    sm2_show_bigint(&ctx->d);
    printf("===================================");
    printf("===================================\n");
}

// Write to files
void sm2_write_bytes(FILE *file, const uint8_t *bytes, uint32_t byte_len) {
    for (uint64_t i = 0; i < byte_len; ++i) {
        fprintf(file, "%02X", bytes[i]);
        /*
        if (i % 4 == 3 && with_space) {
            fprintf(file, " ");
        }
        */
    }
    fprintf(file, "\n");
}
void sm2_write_bitstring(FILE *file, const sm2_bitstring *bs) {
    if (file == NULL || bs == NULL) return;
    for (uint64_t i = 0; i < bs->byte_len; ++i) {
        fprintf(file, "%02X", bs->data[i]);
    }
    fprintf(file, "\n");
}

void sm2_write_bigint(FILE *file, const sm2_bigint *x) {
    if (file == NULL || x == NULL) return;
    for (int i = SM2_BIGINT_DATA_LEN - 1; i >= 0; --i) {
        fprintf(file, "%08X", (unsigned int) x->data[i]);
    }
    fprintf(file, "\n");
}

